﻿using Single.Sugar.Entity;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Single.Sugar.Db
{
    public class DbRepository<T> : SimpleClient<T> where T : BaseEntity, new()
    {
        private static string[] updateFields = { "UpdataeUserId", "UpdateUserName", "UpdateTime" };

        public DbRepository(ISqlSugarClient context) : base(context) { }

        public virtual T UpdateTreePathNode(T updateObj, Expression<Func<T, object>> pidExpr, Expression<Func<T, object>> pathExpr)
        {
            Type type = typeof(T);

            string GetPropertyName<T>(Expression<Func<T, object>> expr)
            {
                var propertyName = string.Empty;

                if (expr.Body is UnaryExpression)
                {
                    propertyName = ((MemberExpression)((UnaryExpression)expr.Body).Operand).Member.Name;
                }
                else if (expr.Body is MemberExpression)
                {
                    propertyName = ((MemberExpression)expr.Body).Member.Name;
                }
                else if (expr.Body is ParameterExpression)
                {
                    propertyName = ((ParameterExpression)expr.Body).Type.Name;
                }

                return propertyName;
            }

            var pidField = GetPropertyName(pidExpr);
            var pidProperty = type.GetProperty(pidField);

            var pathField = GetPropertyName(pathExpr);
            var pathProperty = type.GetProperty(pathField);

            var objPid = pidProperty?.GetValue(updateObj)?.ToString();

            if (!objPid.Equals("0"))
            {
                var parent = GetById(objPid);
                var parentPath = pathProperty?.GetValue(parent)?.ToString();
                pathProperty?.SetValue(updateObj, $"{parentPath}{parent.Id}|");
            }
            else { pathProperty?.SetValue(updateObj, "|0|"); }

            return updateObj;
        }

        public override bool InsertOrUpdate(T data)
        {
            return Context.Storageable(data).DefaultAddElseUpdate().ExecuteCommand() > 0;
        }

        public virtual bool UpdateExcept(T updateObj, params string[] properties)
        {
            return AsUpdateable(updateObj).IgnoreColumns(properties).ExecuteCommand() > 0;
        }

        public virtual bool UpdateFields(T updateObj, params string[] properties)
        {
            return AsUpdateable(updateObj).UpdateColumns(updateFields.Concat(properties).ToArray(), true).ExecuteCommand() > 0;
        }

        public virtual bool UpdateRangeExcept(T[] updateObjs, params string[] properties)
        {
            return AsUpdateable(updateObjs).IgnoreColumns(properties).ExecuteCommand() > 0;
        }

        public virtual bool UpdateRangeeExcept(List<T> updateObjs, params string[] properties)
        {
            return AsUpdateable(updateObjs).IgnoreColumns(properties).ExecuteCommand() > 0;
        }

        public virtual bool UpdateRangeFields(T[] updateObjs, params string[] properties)
        {
            return AsUpdateable(updateObjs).UpdateColumns(updateFields.Concat(properties).ToArray(), true).ExecuteCommand() > 0;
        }

        public virtual bool UpdateRangeFields(List<T> updateObjs, params string[] properties)
        {
            return AsUpdateable(updateObjs).UpdateColumns(updateFields.Concat(properties).ToArray(), true).ExecuteCommand() > 0;
        }

        public virtual IFastest<T> Fastest()
        {
            return Context.Fastest<T>();
        }
    }
}